package com.example.java_chatroom.component;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;

import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 通过这个类来记录当前用户在线的状态. (维护了 userId 和 WebSocketSession 之间的映射)
 */
@Slf4j
@Component
public class OnlineUserManager {
    /**
     * 上线sessionHash管理
     * 此处这个 哈希表 要考虑到线程安全问题.
     */
    private ConcurrentHashMap<Integer, WebSocketSession> onlineSessions = new ConcurrentHashMap<>();

    /**
     * 用户上线, 给这个哈希表中插入键值对
     * TODO  这块想改造一下，把后面上线的可以把前面的挤下去
     * @param userId        上线的用户id
     * @param session       当前上线分配的 webSocketSession
     */
    public void online(int userId, WebSocketSession session) {
        // 查一下当前用户是否已经登录过
        if (getSession(userId) != null) {
            // 此时说明用户已经在线了, 就登录失败, 不会记录这个映射关系.
            // 不记录这个映射关系, 后续就收不到任何消息 (毕竟, 咱们此处是通过映射关系来实现消息转发的)
            log.info("[{}}] 已经被登录了, 登录失败!", userId);
            // 防止多开，已经跟进过，直接返回
            return;
        }
        // 放到上线sessionHash表中
        onlineSessions.put(userId, session);
        log.info("[{}}] 用户上线啦!", userId);
    }

    /**
     * 用户下线, 针对这个哈希表进行删除元素
     * @param userId        下线的用户id
     * @param session       当前行走的 webSocketSession
     */
    public void offline(int userId, WebSocketSession session) {
        // 查询该用户是否已经存在webSocket会话
        WebSocketSession existSession = getSession(userId);
        // 判断当前送进来的 WebSocket 会话是否是用户所拥有的 WebSocket 会话
        if (existSession == session) {
            // 如果这俩 session 是同一个, 才真正进行下线操作. 否则就啥都不干
            onlineSessions.remove((userId));
            log.info("[{}}] 用户下线啦!", userId);
        }
    }

    /**
     * 根据 userId 获取到 WebSocketSession
     * @param userId        用户id
     * @return      返回一个查询结果
     */
    public WebSocketSession getSession(int userId) {
        return onlineSessions.get(userId);
    }
}
